package gestoresHabitacion;





import Control.EntityMan;
import Control.EstadiaJpaController;
import Control.FueraServicioJpaController;
import Control.HabitacionJpaController;
import Control.ReservaJpaController;
import Entidades.Estadia;
import Entidades.FueraServicio;
import Entidades.Habitacion;
import Entidades.Pasajero;
import Entidades.Reserva;
import Entidades.Tarifa;
import Excepciones.*;
import interfaz.MostrarEstadoHabitacion;
import java.sql.Time;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import java.util.TreeMap;

import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JOptionPane;



public class GestorHabitacion {
     private static GestorHabitacion singleton=new GestorHabitacion();
      //formateamos la fecha
     private SimpleDateFormat formatoFecha = new SimpleDateFormat("dd/MM/yyyy");
	 
	
	
	public GestorHabitacion() {
		// TODO Auto-generated constructor stub
	}
	
        public static GestorHabitacion getInstance(){
        return singleton;}
        
	/*METODOS DEL GESTOR*/
        
        //este metodo crea y devuelve un mapa cuyas claves son los dias del rango solicitado, y de valor otro mapa con el estado de las habitaciones
	public Map<Date,Map<Habitacion, String>> comprobarEstado(String Desde, String Hasta){
                   
       //obtenermos las habitaciones del hotel
            HabitacionJpaController gestorHabitacionesBD= new HabitacionJpaController(EntityMan.getInstance());
        List <Habitacion> listaHab =gestorHabitacionesBD.findHabitacionEntities();
        
        //creamos el mapa el cual retornara los estados de cada habitacion por cada fecha
        Map<Date,Map<Habitacion, String>> mapaEstados=new TreeMap<>();
        
        
        //iteramos para obtener los estados en el rango
          try {
            //seteamos la fecha del rango de busqueda de estados
            // desde aqui empieza el recorrido
            Date intervalo= formatoFecha.parse(Desde);
            // este es el limite.
             Date fecha_fin= formatoFecha.parse(Hasta);
              
        while (intervalo.getTime() <= fecha_fin.getTime() ){
            
            Date unaFecha=new Date(intervalo.getTime());
            
           //creamos un map con todas las habitaciones disponibles por default  
            Map<Habitacion, String> mapaHabitaciones=new HashMap<>();
            for(Habitacion hab: listaHab){
                mapaHabitaciones.put(hab,"D");
               
            }
            mapaEstados.put(unaFecha, mapaHabitaciones);
         
            //cargamos las habitaciones que estan fuera de servicio
            List <Habitacion> habitacionesFS=verHabitacionesFS(unaFecha);
            for(Habitacion habFS: habitacionesFS){
                mapaEstados.get(unaFecha).put(habFS, "FS");}
           
              //cargamos las habitaciones que estan Reservadas
            List <Habitacion> habitacionesReservadas=verHabitacionesReservadas(unaFecha);
            for(Habitacion habRes: habitacionesReservadas){
                mapaEstados.get(unaFecha).put(habRes, "R");}
            
                //cargamos las habitaciones que estan Ocupadas
            List <Habitacion> habitacionesOcupadas=verHabitacionesOcupadas(unaFecha);
            for(Habitacion habOcup: habitacionesOcupadas){
                mapaEstados.get(unaFecha).put(habOcup, "O");}
            
            
        // Incrementamos un dia(86400000 es un dia en milisegundos)
        intervalo.setTime((long) intervalo.getTime()+(86400000));
}     
		
                
		  } catch (ParseException ex) {
            Logger.getLogger(MostrarEstadoHabitacion.class.getName()).log(Level.SEVERE, null, ex);
        }
          return mapaEstados;
	}
	
	//validamos las fechas recibidas
	public boolean validarFechas(String Desde, String Hasta)throws FechaInvalidaException{
            Date actual=new Date();
	boolean ret=true;
             if(!isFechaValida(Desde)){
                 ret=false;
                 throw new FechaInvalidaException("Formato de Fecha Desde incorrecto: dd/mm/aaa");}
              if(!isFechaValida(Hasta)){       
              ret=false;
                  throw new FechaInvalidaException("Formato de Fecha Hasta incorrecto: dd/mm/aaa");
              }
            
            
             try {
           
            Date ini= formatoFecha.parse(Desde);
            Date fin= formatoFecha.parse(Hasta);
            
            if(!(ini.getTime()<=fin.getTime())){
                ret=false;
            throw new FechaInvalidaException("Fecha Desde debe ser posterior a Hasta");}
           
    //aca se valida que las habitaciones se busquen para ocupar en una fecha futura a hoy
    //esta deshabilitado esto porque las habitaciones ya ocupadas y reservada son con fechas anteriores
            /*if (!(actual.getTime()<=ini.getTime())){ 
                ret=false;
               throw new FechaInvalidaException("La fecha debe ser posterior al dia de la fecha");}*/
		  
             } catch (ParseException ex) {
            Logger.getLogger(MostrarEstadoHabitacion.class.getName()).log(Level.SEVERE, null, ex);
             }
            
           
             return ret;
                
        }
        //metodo auxiliar para verificar la fecha
     private static boolean isFechaValida(String fecha) {
     try {
            SimpleDateFormat formatoFecha = new SimpleDateFormat("dd/MM/yyyy", Locale.getDefault());
            formatoFecha.setLenient(false);
            formatoFecha.parse(fecha);
        } catch (ParseException e) {
            return false;
        }
        return true;
    }

	private boolean validarCampos(){
		
		
		return false;
	}
	
	
	
	public Estadia ocuparHabitacion(int numero, Pasajero responsable,String desde, String hasta){
               
                    EstadiaJpaController estadiasBD= new EstadiaJpaController(EntityMan.getInstance());
                    HabitacionJpaController habitacionesBD= new HabitacionJpaController(EntityMan.getInstance());
                    int id=estadiasBD.getEstadiaCount()+1;
                    Date Desde=new Date();
                    Date Hasta= new Date();
                    try {
                        Desde= formatoFecha.parse(desde);
                        Hasta= formatoFecha.parse(hasta);
                      }catch (ParseException ex) {
                        Logger.getLogger(GestorHabitacion.class.getName()).log(Level.SEVERE, null, ex);   
                    }
                    
                    Estadia nuevaEstadia=new Estadia(id, Desde, Hasta,responsable.getIdPasajero());
                    nuevaEstadia.setHabitacion(habitacionesBD.findHabitacion(numero));
                   
                  return nuevaEstadia;
	}
        //guarda la estadia una vez que se han guardado todos los datos y pasajeros
        public void guardarEstadia(Estadia nuevaEstadia){
        EstadiaJpaController estadiasBD= new EstadiaJpaController(EntityMan.getInstance());
         try {
                    estadiasBD.create(nuevaEstadia);
                    }
                    catch (Exception ex) {
                    Logger.getLogger(GestorHabitacion.class.getName()).log(Level.SEVERE, null, ex);
                    }
        }
        
        public Estadia añadirPasajerosEnEstadia(Estadia estadiaEditada, List <Pasajero> ocupantesNuevos) throws PasajeroHabitacionRepetidoException{
         
             
            List <Pasajero> ocupantesActuales=estadiaEditada.getPasajeroList();
             
             //agregamos los nuevos pasajeros si no hay ninguno cargado
             if(ocupantesActuales==null){
             estadiaEditada.setPasajeroList(ocupantesNuevos);}
             
             else{
                 for(Pasajero unPasajero: ocupantesNuevos){
                 if(ocupantesActuales.contains(unPasajero)){
                     throw new PasajeroHabitacionRepetidoException(unPasajero.getNombre(),unPasajero.getApellido());
                     
                 }else{
                      //obtenemos los pasajero ya cargados en la habitacion
                   
             ocupantesActuales.addAll(ocupantesNuevos);
             estadiaEditada.setPasajeroList(ocupantesActuales);
             }
                 }
        
       
        
             }
              return estadiaEditada;
        }
        
        
	public boolean checkoutHabitacion(Habitacion unaHabitacion, Time hora_egreso){
		return false;};
        
	public boolean reservarHabitacion(Habitacion unaHabitacion, List <String> datosReserva,Date desde, Date hasta){
		
		Reserva nuevaReserva;
		
		return false;
	}
	
	public void procesarSeleccionada(int numero, Map<String,String> estados) throws HabitacionReservadaException, HabitacionOcupadaException, HabitacionDisponibleException,HabitacionFueraServicioException{
            
           
           List< String> resultado=new ArrayList<>();
            //esta lista se utiliza para transforma el Set de clave, en una lista a medida que recorro en el for
            List <String> fechasSeleccionadas=new ArrayList<>();
                    
         
            for(String fecha: estados.keySet()){
                fechasSeleccionadas.add(fecha);
                if(estados.get(fecha).equals("O")){
                resultado.add("Ocupada");}
                
                else if(estados.get(fecha).equals("R")){
                resultado.add("Reservada");}
                
                else  if(estados.get(fecha).equals("FS")){
                resultado.add("Fuera de Servicio");}
                
          
            }
            
        if(resultado.contains("Ocupada")) {
                 
                throw new HabitacionOcupadaException();
          }
            else if(resultado.contains("Fuera de Servicio")) {
                 
                throw new HabitacionFueraServicioException();
          }
        else if(resultado.contains("Reservada")){
                
                //creamos una lista de parametros para informar quien tiene la reserva
              List< List <String>> datosReserva= verDatosReserva(numero, estados);
               //añadimos datos sobre la habitacion a ocupar por si se desea ocupar igual
               datosReserva.get(0).add(fechasSeleccionadas.get(0));  //fecha inicial estadia
               datosReserva.get(0).add(fechasSeleccionadas.get(fechasSeleccionadas.size()-1) ); //fecha final estadia
               datosReserva.get(0).add(((Integer)numero).toString());  //numero de hab a ocupar
              
              throw new HabitacionReservadaException(datosReserva );
            }
          
        else {
              throw new HabitacionDisponibleException(numero,fechasSeleccionadas.get(0), fechasSeleccionadas.get(fechasSeleccionadas.size()-1));
        }
            
		
		
	}
	
	private Estadia estadiaActual(Habitacion unaHabitacion){
		return null;}
        
	private List<Tarifa> verTarifas(){
		
            
		return null;
		
		
	}
	
// metodo que retorna una lista con las habitaciones que se encuentran Fuera de Servicio en un determinado dia
	private List<Habitacion> verHabitacionesFS(Date dia){
           
             FueraServicioJpaController habFueraServicioBD= new FueraServicioJpaController(EntityMan.getInstance());
            
        
         List<Habitacion> resultadosFS=new ArrayList<>();
         
         for(FueraServicio habFS:habFueraServicioBD.findFueraServicioEntities()){
             
             if(habFS.getFueraServicioPK().getDesde().getTime()<=dia.getTime() && habFS.getFueraServicioPK().getHasta().getTime()>=dia.getTime()){
                
             resultadosFS.add(habFS.getHabitacion());
             }
         }
	
		return resultadosFS;
	}
// metodo que retorna una lista con las habitaciones que se encuentran Reservadas en un determinado dia        
        	private List<Habitacion> verHabitacionesReservadas(Date dia){
           
             ReservaJpaController reservasBD= new ReservaJpaController(EntityMan.getInstance());
            
        
         List<Habitacion> resultadosReservadas=new ArrayList<>();
         
         for(Reserva res:reservasBD.findReservaEntities()){
             
             if(res.getIngreso().getTime()<=dia.getTime() && res.getEgreso().getTime()>=dia.getTime()){
                
             resultadosReservadas.add(res.getHabitacion());
             }
         }
	
		return resultadosReservadas;
	}
                
// metodo que retorna una lista con las habitaciones que se encuentran Ocupadas en un determinado dia        
        	private List<Habitacion> verHabitacionesOcupadas(Date dia){
           
             EstadiaJpaController estadiasBD= new EstadiaJpaController(EntityMan.getInstance());
            
        
         List<Habitacion> resultadosOcupadas=new ArrayList<>();
         
         for(Estadia est: estadiasBD.findEstadiaEntities()){
             
             if(est.getDiaIngreso().getTime()<=dia.getTime() && est.getDiaEgreso().getTime()>=dia.getTime()){
                
             resultadosOcupadas.add(est.getHabitacion());
             }
         }
	
		return resultadosOcupadas;
	}
  
//metodo que devuelve los datos de la persona que tiene la reserva de una habitacion
 private List<List <String>> verDatosReserva(int numero, Map<String,String> estados){
                 //lista con la lista de datos  de todas las reservas   
               List< List<String>> resultados=new ArrayList<>();
                //lista con los datos de una reserva
                List <String> unaReserva=new ArrayList<>();
                
                   ReservaJpaController reservasBD= new ReservaJpaController(EntityMan.getInstance());
                    List <String> fechas=new ArrayList<>();
                    //obtenemos las reservas de la BD
                    List <Reserva> todasReservas=reservasBD.findReservaEntities();
                   
                    //aquie se van guardando las reservas en el intervalo que se ha seleccionado
                    List <Reserva> reservasFiltradas=new ArrayList<>();
                
                    for(String fecha: estados.keySet()){
                
                if(estados.get(fecha).equals("R")){
                fechas.add(fecha);}
                   }
                for(String fechaReserva: fechas){
                    
                
                for(Reserva res: todasReservas){
                    
             
                try {
                    if(res.getHabitacion().getNumero().equals(numero)&&res.getIngreso().getTime()<=(formatoFecha.parse(fechaReserva)).getTime() && res.getEgreso().getTime()>=(formatoFecha.parse(fechaReserva)).getTime()&&(!reservasFiltradas.contains(res))){
                      reservasFiltradas.add(res);
                    }   
                } catch (ParseException ex) {
                           Logger.getLogger(GestorHabitacion.class.getName()).log(Level.SEVERE, null, ex);
                       }
                }}
                //añadimos los datos de cada reserva distinta al la lista de resultados
                for( Reserva res: reservasFiltradas){
                        unaReserva=new ArrayList<>();
                    unaReserva.add(res.getNombre().concat(" ").concat(res.getApellido()));
                       unaReserva.add(formatoFecha.format(res.getFechaReserva()));
                       unaReserva.add(formatoFecha.format(res.getIngreso()));
                       unaReserva.add(formatoFecha.format(res.getEgreso()));
                       unaReserva.add(String.valueOf(res.getTelefono()));
                       
                       resultados.add(unaReserva);
                }
  

	return resultados;
                }
}
